package exception;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.sql.SQLSyntaxErrorException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import util.AjaxResultDto;
import com.alibaba.fastjson.JSONObject;


public class CustomSimpleMappingExceptionResolver extends SimpleMappingExceptionResolver { 
    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // Expose ModelAndView for chosen error view.
        String viewName = determineViewName(ex, request);
        if (viewName != null) {// JSP格式返回
            if (!(request.getHeader("accept").indexOf("application/json") > -1 || (request.getHeader("X-Requested-With") != null && request
                .getHeader("X-Requested-With").indexOf("XMLHttpRequest") > -1))) {
                // 如果不是异步请求
                // Apply HTTP status code for error views, if specified.
                // Only apply it if we're processing a top-level request.
                Integer statusCode = determineStatusCode(request, viewName);
                if (statusCode != null) {
                    applyStatusCodeIfPossible(request, response, statusCode);
                }
                return getModelAndView(viewName, ex, request);
            }
            else {// JSON格式返回
                try {
                    PrintWriter writer = response.getWriter();
                    writer.write(ex.getMessage());
                    writer.flush();
                }
                catch (IOException e) {
                   // e.printStackTrace();
                }
                return null;

            }
        }
        else {
            return null;
        }
    }
    
	@Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        String viewName = determineViewName(ex, request);
        if (viewName != null) {// JSP格式返回
                try {
                	//1.普通ajax操作异常
                    AjaxResultDto result = new AjaxResultDto();
                    PrintWriter writer = response.getWriter();
                    if (ex instanceof BusinessException) {
                        String exMessage = ex.getMessage();
                        result.setIsError(true);
                        result.setErrorMsg(exMessage);
                        result.setErrorCode(((BusinessException) ex).getCode());
                    }else if(ex instanceof HTTPClientException){
                    	String exMessage = ex.getMessage();
                        result.setIsError(true);
                        result.setErrorMsg(exMessage);
                        result.setErrorCode(((HTTPClientException) ex).getCode());
                    }else {
                        Map<String, String> resultException = createCommonMessageByExcepiton(ex);
                        String exMessage = resultException.get("message");
                        String code = resultException.get("code");
                        result.setIsError(true);
                        result.setErrorMsg(exMessage);
                        result.setErrorCode(code);
                    }
                    JSONObject obj = (JSONObject) JSONObject.toJSON(result);
                    
                    writer.print(obj);
                    writer.flush();
                    writer.close(); 
                }
                catch (Exception e) {
                   // e.printStackTrace();
                }
                return null;
        }
        else {
            return null;
        }
    }
    
    

    /**
     * 根据原始异常信息，生成易于理解的出错信息
     * 
     * @param e
     * @return
     */
    private Map<String, String> createCommonMessageByExcepiton(Exception e) {
        Map<String, String> resultException = new HashMap<String, String>();
        String message = null;
        String code = null;
        if (e instanceof SQLSyntaxErrorException) {
            message = processSQLSyntaxErrorException(e);
            code = "10001";
        }
        else if (e instanceof SQLException) {
            message = processSQLException(e);
            code = "10002";
        }
        else if (e instanceof NullPointerException) {
            message = processNullPointerException(e);
            code = "10003";
        }
        else if (e instanceof ClassNotFoundException) {
            message = processClassNotFoundException(e);
            code = "10004";
        }
        else if (e instanceof FileNotFoundException) {
            message = processFileNotFoundException(e);
            code = "10005";
        }
        else if (e instanceof ClassCastException) {
            message = processClassCastException(e);
            code = "10006";
        }
        else if (e instanceof IOException) {
            message = processIOException(e);
            code = "10007";
        }
        else if (e instanceof ArrayIndexOutOfBoundsException) {
            message = "数组越界，当前的index为：" + e.getLocalizedMessage();
            code = "10008";

        }
        else if (e instanceof IndexOutOfBoundsException) {
            code = "10009";

        }
        else if (e instanceof NumberFormatException) {
            message = processNumberFormatException(e);
            code = "10010";
        }
        else {
            message = e.getLocalizedMessage();
            code = "10011";
        }
        resultException.put("code", code);
        resultException.put("message", message);
        return resultException;
    }


    /**
     * 处理IndexOutOfBoundsException
     */
    @SuppressWarnings("unused")
    private static String processIndexOutOfBoundsException(Exception e) {
        String message = e.getLocalizedMessage();
        if (message.startsWith("Index:")) {
            message =
                    "index越界，当前的index为：" + message.substring(message.indexOf(":") + 1, message.indexOf(",")) + "容器的容量是："
                            + message.substring(message.lastIndexOf(":") + 1);
        }
        return message;
    }


    /**
     * 处理SQLSyntaxErrorException
     * 
     * @param e
     * @return
     */
    private String processSQLSyntaxErrorException(Exception e) {
        String errorMessage = e.getMessage();
        if (errorMessage.startsWith("You have an error")) {
            errorMessage += "sql有语法错误，在" + errorMessage.substring(errorMessage.indexOf("near") + 4);
        }
        else {
            errorMessage = e.getLocalizedMessage();
        }
        return errorMessage;
    }


    /**
     * 处理SQLException
     * 
     * @param e
     * @return
     */
    private String processSQLException(Exception e) {
        String errorMessage = e.getMessage();
        if (errorMessage.startsWith("You have an error")) {
            errorMessage += "sql有语法错误，在" + errorMessage.substring(errorMessage.indexOf("near") + 4);
        }
        else {
            errorMessage = e.getLocalizedMessage();
            if (errorMessage.contains("\n")) {
                errorMessage = errorMessage.replaceAll("\n", " ");

            }
        }
        return errorMessage;
    }


    /**
     * 处理 NullPointException
     * 
     * @param e
     */
    private String processNullPointerException(Exception e) {
        String message = "空指针异常：" + e.getMessage() + "\n";
        StackTraceElement[] arr = e.getStackTrace();
        // 缩短stackTrace
        for (int i = 0; i < (arr.length < 4 ? arr.length : 3); i++) {
            message += arr[i].getClassName() + "(" + arr[i].getMethodName() + ":" + arr[i].getLineNumber() + ")\n";
        }
        return message;
    }


    /**
     * 处理FileNotFoundException
     * 
     * @param e
     */
    private String processFileNotFoundException(Exception e) {
        return e.getLocalizedMessage() + "文件找不到！";
    }


    /**
     * 处理ClassCastException
     */
    private String processClassCastException(Exception e) {
        String message = e.getLocalizedMessage();
        String arr[] = message.split("cannot be cast to");
        message = arr[0] + "不能强转为：" + arr[1];
        StackTraceElement st = e.getStackTrace()[0];
        message += "\n " + st.getClassName() + "(" + st.getMethodName() + ":" + st.getLineNumber() + ")";
        return message;
    }


    /**
     * 处理ClassNotFoundException
     * 
     * @param e
     */
    private String processClassNotFoundException(Exception e) {
        return "缺少" + e.getLocalizedMessage() + "类，请查找是否存在相关jar或者class文件!";
    }


    /**
     * 处理NumberFormatException
     * 
     * @param args
     */
    private String processNumberFormatException(Exception e) {
        String message = e.getLocalizedMessage();
        if (message.startsWith("For input string:")) {
            message = "数字格式异常,输入的字符串为：" + message.replace("For input string:", "");
        }
        return message;
    }


    /**
     * 处理IOException
     * 
     * @param e
     */
    private static String processIOException(Exception e) {
        String message = e.getLocalizedMessage();
        if (message.startsWith("Read error")) {
            message = "文件读取失败！输入流可能已经关闭！";
        }
        else if (message.startsWith("Write error")) {
            message = "文件写入失败！输出流可能已经关闭！";
        }
        return message;
    }
}